#include "threadPool.h"
#include "vds.h"
#include "../tlv/tlv.h"
#include "../ftp/ftp.h"

void *callback(tlv_t *tlv, int sockfd, uint8_t type, uint32_t length, const uint8_t *value,void *){
    vds_t *vds = (vds_t*)pthread_getspecific(key);
    int ret;
    char response[TLV_VALUE_MAX_SIZE];
    int already_response = 0;
    switch(type){
    case REQUEST_CMD_CD: {
                             ret = vds_cd(vds,(const char *)value);
                             if (ret == 0) {
                                 strcpy(response, "OK Directory changed");
                             } else {
                                 const char *err_str = vds_error(vds);
                                 snprintf(response, sizeof(response), "ERROR %s", err_str);
                             }
                             break;
                         }
    case REQUEST_CMD_LS: {
                             ret = vds_ls(vds, length > 1 ? (const char *)value : ".", response, sizeof(response));
                             if (ret != 0) {
                                 const char *err_str = vds_error(vds);
                                 snprintf(response, sizeof(response), "ERROR %s", err_str);
                             }
                             break;
                         }
    case REQUEST_CMD_PWD: {
                              char *pwd = vds_pwd(vds, NULL);
                              if (pwd) {
                                  strcpy(response, pwd);
                                  free(pwd);
                              } else {
                                  const char *err_str = vds_error(vds);
                                  snprintf(response, sizeof(response), "ERROR %s", err_str);
                              }
                              break;
                          }
    case REQUEST_CMD_MKDIR: {
                                ret = vds_mkdir(vds, (const char *)value);
                                if (ret == 0) {
                                    strcpy(response, "OK Directory created");
                                } else {
                                    const char *err_str = vds_error(vds);
                                    snprintf(response, sizeof(response), "ERROR %s", err_str);
                                }
                                break;
                            }
    case REQUEST_CMD_PUTS: {
                               char file_path[1024];
                               vds_real_path(vds,(const char*)value,file_path);
                               puts(file_path);
                               if(tlv_response(tlv,sockfd,sizeof(response)+1,(const uint8_t*)response) == -1){
                                   already_response = 1; 
                                   return (void *)-1;   
                               }
                               recv_file(sockfd,file_path);
                               break;
                           }
    case REQUEST_CMD_GETS: {
                               char file_path[1024];
                               vds_real_path(vds,(const char*)value,file_path);
                               puts(file_path);
                               if(tlv_response(tlv,sockfd,sizeof(response)+1,(const uint8_t*)response) == -1){
                                   already_response = 1; 
                                   return (void *)-1;
                               }
                               send_file(sockfd,file_path);
                               break;
                           }  
    case REQUEST_CMD_RMDIR: {
                                ret = vds_rmdir(vds, (const char*)value);
                                if (ret == 0) {
                                    strcpy(response, "OK Directory removed");
                                } else {
                                    const char *err_str = vds_error(vds);
                                    snprintf(response, sizeof(response), "ERROR %s", err_str);
                                }
                                break;
                            }
    case REQUEST_CMD_EXIT: {
                               strcpy(response, "OK Goodbye");
                               break;
                           }
    default: {
                 strcpy(response, "ERROR Unknown command");
                 break;
             }
    }

    if(!already_response){
        tlv_response(tlv, sockfd, strlen(response)+1,(const uint8_t *)response);
    }
    return NULL;
}

int clientHandler(int client_fd) {
    tlv_t tlv;
    char username[256];
    char password[256];
    int pass = 0;
    uint8_t type;
    uint32_t length;
    while(!pass){
        int ret = tlv_recv(&tlv, client_fd, &type, &length);
        if(ret == -1){
            close(client_fd);
            return -1;
        }
        sscanf((const char *)tlv.buffer,"%s %s",username,password);
        pass = !check(username,password);
        uint8_t response_code = pass ? 100 : 90;
        tlv_response(&tlv,client_fd,sizeof(response_code),&response_code);
    }
    // 初始化 vds
    vds_t *vds = vds_init(".");
    if (vds == NULL) {
        send(client_fd, "ERROR Initialization failed", 22, 0);
        close(client_fd);
        return -1;
    }

    pthread_setspecific(key,vds);
    while(1){
        int ret = tlv_listen(&tlv,client_fd,callback,NULL);
        if(ret == -1){
            if(tlv.error_type == TLV_E_CONNECT_IS_OVER){
                printf("client_fd %d is disconnected\n",client_fd);
            }
            else{
                printf("tlv_listen :%s\n",tlv_error_str(&tlv));
            }
            break;
        }


    }
    vds_free(vds);
    close(client_fd);
    return 0;
}
